#include "ClienteAhorcado.h"
#include <stdio.h>
#include <conio.h>
#include <iostream>
#include <string.h>
#include "MessageIdentifiers.h"
#include "BitStream.h"
#include "RakNetTypes.h"  // MessageID
#include "GameMessageId.h"
#include "GameMessage.h"
#include "ServerConfigs.h"
#include "PacketParser.h"
#include <sstream>
#include "HandleInput.h"

ClienteAhorcado::ClienteAhorcado()
{
	peer = RakNet::RakPeerInterface::GetInstance();
}

void ClienteAhorcado::play()
{	
	getClientName();
	prepareConnection();
	while (1)
	{
		managePackages();
		update();
		if(exitCheck())
			break;
	}
	RakNet::RakPeerInterface::DestroyInstance(peer);
}

void ClienteAhorcado::getClientName()
{
	std::cout << "Elija un nombre para su usuario: ";
	std::cin >> name;
}

void ClienteAhorcado::prepareConnection()
{
	RakNet::SocketDescriptor sd;
	peer->Startup(1,&sd, 1);
	printf("Enter server IP or hit enter for 127.0.0.1\n");
	gets(serverAddressStr);
	if (serverAddressStr[0]==0){
		strcpy(serverAddressStr, "127.0.0.1");
	}
	printf("Starting the client.\n");
	int portListening = SERVER_PORT;
	peer->Connect(serverAddressStr, SERVER_PORT, 0,0,0,0,12U,500U,0);
	serverAddress = RakNet::SystemAddress(serverAddressStr, SERVER_PORT);

	state = ClienteState::waiting;
}

void ClienteAhorcado::managePackages()
{
	RakNet::Packet *packet;// = NULL;
	GameMessage* gm = NULL;
	bool readPackage = true, fakePacketOn = false;
	for (packet=(readPackage)?peer->Receive():packet; packet; peer->DeallocatePacket(fakePacketOn? NULL: packet), packet=(readPackage)?peer->Receive():packet)
		{
			readPackage = true;
			if(fakePacketOn){
				bool play = true, conAcpt = true; unsigned char fuckingUC;
				packet = new RakNet::Packet();
				packet->data = play? (
					new GameMessage(GameMessageId::YOU_PLAY,"****"))->toCharPointer() :
				&(fuckingUC = DefaultMessageIDTypes::ID_CONNECTION_REQUEST_ACCEPTED);
				packet->length = std::strlen((char*)packet->data);
				packet->systemAddress = RakNet::SystemAddress("127.0.0.1",SERVER_PORT);
			}
			switch (packet->data[0])
			{
			case ID_REMOTE_DISCONNECTION_NOTIFICATION:
				printf("Another client has disconnected.\n");
				break;
			case ID_REMOTE_CONNECTION_LOST:
				printf("Another client has lost the connection.\n");
				break;
			case ID_REMOTE_NEW_INCOMING_CONNECTION:
				printf("Another client has connected.\n");
				break;
			case ID_CONNECTION_REQUEST_ACCEPTED:
				{
					printf("Our connection request has been accepted.\n");
					printf("Press enter to set ready.\n");
					state = ClienteState::notReady;
				}
				break;
			case ID_NEW_INCOMING_CONNECTION:
				printf("A connection is incoming.\n");
				break;
			case ID_NO_FREE_INCOMING_CONNECTIONS:
				printf("The server is full.\n");
				break;
			case ID_DISCONNECTION_NOTIFICATION:
				printf("We have been disconnected.\n");
				break;
			case ID_CONNECTION_LOST:
				printf("Connection lost.\n");
				break;
			case ID_CONNECTION_ATTEMPT_FAILED:
				printf("Server not responding.\n");
				peer->Connect(serverAddressStr, SERVER_PORT, 0,0,0,0,12U,500U,0);
				break;
			case YOU_PLAY:
				{
					if(fakePacketOn)
					{
						gm = new GameMessage(packet->data);
					}
					else{
						gm = new GameMessage();
						PacketParser::toGameMessage(gm,packet);
					}
					switch(state)
					{
					case ClienteState::playing:
						if(strcmp(curWordState.c_str(),gm->getMessageStr().c_str())==0)
						{
							//ignore, no changes have been made
						}else
						{
							curWordState = gm->getMessageStr();
							printf("Current word: %s.\n", curWordState);
						}
						break;
					case ClienteState::waiting:
						state = ClienteState::playing;
						printf("Is your turn.\n");
						curWordState = gm->getMessageStr();
						printf("Current word: %s.\n",curWordState.c_str());
						break;
					}
					if(gm){
						delete gm;
						gm = NULL;
					}
				}
				break;
			case YOU_WAIT:
				gm = new GameMessage();
				PacketParser::toGameMessage(gm,packet);
				if(playerPlaying.compare(gm->getMessageStr())==0)
				{
					//Nothing new
					break;
				}else
				{
					state = ClienteState::waiting;
					lastPlayerPlaying = playerPlaying;
					playerPlaying = gm->getMessageStr();
				}
				if(gm){
						delete gm;
						gm = NULL;
				}
				break;
			case YOU_WON:
				state = ClienteState::won;
				break;
			case YOU_LOST:
				state = ClienteState::lost;
				gm = new GameMessage();
				PacketParser::toGameMessage(gm,packet);
				playerWinning = gm->getMessageStr();
				if(gm){
						delete gm;
						gm = NULL;
				}
				break;
			default:
				printf("Message with identifier %i has arrived.\n", packet->data[0]);
				break;
			}
		}
}

void ClienteAhorcado::update()
{
	RakNet::Packet *packet = NULL;
	bool kbHited;
	int charEntry;
	std::string strInput;
	switch (state)
	{
		case notReady:
			if(HandleInput::getCharAsynchronously()==13)
			{
				state = ClienteState::ready;
				//GameMessage* readyMsg = new GameMessage(GameMessageId::LOBBY_PLAYER_READY, name);
				RakNet::BitStream bsOut;
				bsOut.Write((RakNet::MessageID)GameMessageId::LOBBY_PLAYER_READY);
				bsOut.Write(RakNet::RakString(name.c_str())); //why god, why
				uint32_t packNumber = peer->Send(&bsOut,HIGH_PRIORITY,RELIABLE_ORDERED,0,serverAddress,false);
				printf("Sended ready msg to server.\n");
				//delete readyMsg;
			}
			break;
		case ready:
			break;
		case playing:
			while( !((kbHited = kbhit()) && (charEntry = getch()) == 13) && (!packet || packet->data[0]== YOU_PLAY))
			{
				if(kbHited)
				{
					if(charEntry == 8)//backspace
						strInput = strInput.substr(0,strInput.size()-1);
					else if(charEntry >= 65 && charEntry <= 122)
						strInput.append((char*)&charEntry);
					printf("%c",charEntry);
				}
				packet=peer->Receive();
				if(packet && !isGameMessageIdValid(packet->data[0]))
				{
					peer->DeallocatePacket(packet);
					packet = NULL; //to avoid crap packets
				}
			}
			/*if(packet && packet->data[0]!=YOU_PLAY){
				readPackage = false;
			}else */if( kbHited && charEntry == 13)
			{
				GameMessage* wordTry = new GameMessage(GameMessageId::CLIENT_WORD, strInput);
				RakNet::BitStream bsOut;
				bsOut.Write(wordTry->toCharPointer());
				peer->Send(&bsOut,HIGH_PRIORITY,RELIABLE_ORDERED,0,serverAddress,false);
				state = waiting;
				delete wordTry;
			}
			break;
		case waiting:
			if(playerPlaying.compare(lastPlayerPlaying)!=0)
			{
				printf("Waiting for player: %s",playerPlaying);
				lastPlayerPlaying = playerPlaying;
			}
			break;
		default:
			break;
	}
}